-
Notifications
You must be signed in to change notification settings - Fork 270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
action_sheet: Add "Mark topic as read" button #1274
base: main
Are you sure you want to change the base?
Conversation
56a877f
to
af14f10
Compare
Hello, I want to know that should I commit the change of icon of "Mark all messages as read button" separately? |
Yeah, committing it separately sounds good. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR! Took a quick look at the implementation and left a comment.
Thanks Alya for pointing. I have updated the correct icon and also updated the PR description with latest screenshots. |
e45f627
to
59fb9c2
Compare
Thanks for the review @PIG208, pushed the revision, PTAL. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the PR! Went through the changes and left some comments, mainly on the tests.
59fb9c2
to
3fcb3b4
Compare
Thanks for the review @PIG208, I have updated the tests and the commit message accordingly. Please have a look and let me know if anything else is required. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the update! Left review comments.
3fcb3b4
to
b0b47b8
Compare
Pushed the changes, Please have a look now @PIG208 , Thanks! |
b0b47b8
to
8451cb2
Compare
Could you also post a screenshot of the topic action sheet with the mark topic as read button on there? For design changes, we prefer screenshots over screen recording, unless it is specific about some interaction. Even then, having both included is helpful. |
Updated the description of PR with screenshot. |
8451cb2
to
7ca77ca
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the update! This mostly looks good to me, with some nits.
32637ff
to
0da9e6b
Compare
Pushed the revision @PIG208, PTAL. Thanks! |
Looks good except for one more nit! Marking it for Greg's review. |
0da9e6b
to
3addbbe
Compare
Figma doesn't specify this icon explicitly. Based on discussions in PR zulip#1274 (zulip#1274 (comment)), we chose this icon for consistency with the "Mark as read" option on web. reference: https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=3512-7&t=iwirdCVutQls9R0A-4
Hi @gnprice, Whenever you have some time, I would really appreciate it if you could review the PR. Thanks a lot! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @lakshya1goel for taking care of this, and thanks @PIG208 and all for the previous reviews! Comments below.
Let's leave out the last commit introducing ZulipAction; that change is mostly a matter of writing docs, so I think it'll be simpler if I just do that change myself rather than going through cycles of editing.
assets/icons/message_checked.svg
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did this icon file come from a particular place in the Figma design, or somewhere else?
Please mention the source in the commit message (with e.g. a Figma link). That helps us track where we've gotten our icons from.
lib/widgets/action_sheet.dart
Outdated
@override void onPressed() async { | ||
if (!pageContext.mounted) return; | ||
await ZulipAction.markNarrowAsRead(pageContext, TopicNarrow(channelId, topic)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, this if-mounted check at the top isn't something we have in any of the comparable methods in this file. I think we can leave it out.
(If there is a reason we need it, then that reason will probably apply equally to all the other buttons.)
Was there a discussion about this in a previous round of review? It's a bit difficult for me to find out from the GitHub page, because of some of GitHub's UI choices. You can mitigate that by avoiding marking comments as "resolved", similar to what Chris said the other day elsewhere: #1317 (review)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, this was not discussed in the previous round. Also, I will not mark the comments as resolved from now on.
test/widgets/action_sheet_test.dart
Outdated
testWidgets('visible if topic has unread messages', (tester) async { | ||
await prepare(); | ||
final message = eg.streamMessage(stream: someChannel, topic: someTopic); | ||
await store.handleEvent(MessageEvent(id: 0, message: message)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can simplify with a handy test helper:
await store.handleEvent(MessageEvent(id: 0, message: message)); | |
await store.addMessage(message); |
test/widgets/action_sheet_test.dart
Outdated
testWidgets('visible if topic has unread messages', (tester) async { | ||
await prepare(); | ||
final message = eg.streamMessage(stream: someChannel, topic: someTopic); | ||
await store.handleEvent(MessageEvent(id: 0, message: message)); | ||
await showFromAppBar(tester, messages: [message]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test is implicitly relying on the fact that eg.streamMessage
returns a message which is unread (doesn't have the read
flag).
In general, test cases should avoid depending on the specific default choices made by the functions in example_data
— each test should be self-contained in that the reader should be able to understand the key logic of how it works just by reading the test itself (and any local helper functions specific to the test), without going and looking through the details of example_data.dart
.
Instead, both this test and the others that care about whether the message is read or unread should explicitly pass flags
to eg.streamMessage
so that they control that fact about the message.
test/widgets/action_sheet_test.dart
Outdated
testWidgets('not visible if topic has no unread messages', (tester) async { | ||
await prepare(); | ||
final message = eg.streamMessage(stream: someChannel, topic: someTopic); | ||
await showFromAppBar(tester, messages: [message]); | ||
check(find.text('Mark topic as read')).findsNothing(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a bit subtle, but the way this test currently works is depending on a bug. 🙂 Namely #649.
The only difference between the setup of this test and the one above it, which gets the opposite result, is that the other test has the message arrive first as an event and then via a fetch, while this one has it arrive only via a fetch. In both cases the message is unread. If we fetch some messages and one of them is described as unread (it lacks the read
flag), then logically there is an unread message in that topic, and the fact that we don't put it into our data structures as such is a bug (namely #649).
So let's instead have this test set things up in a way such that it'll automatically do the right thing even after we fix that bug.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(This also makes an example of why it's valuable to have the test be explicit about the key facts it's relying on in its test data — if this eg.streamMessage
line were explicitly saying the message is unread, instead of implicitly doing so, then it'd naturally raise the question of how that fits with the test description saying this is about not having any unreads.)
test/widgets/action_sheet_test.dart
Outdated
check(connection.lastRequest).isA<http.Request>() | ||
..url.path.equals('/api/v1/messages/flags/narrow') | ||
..bodyFields['narrow'].equals(jsonEncode([ | ||
...TopicNarrow(someChannel.streamId, TopicName(someTopic)).apiEncode(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can simplify a bit with a test helper:
...TopicNarrow(someChannel.streamId, TopicName(someTopic)).apiEncode(), | |
...eg.topicNarrow(someChannel.streamId, someTopic).apiEncode(), |
test/widgets/action_sheet_test.dart
Outdated
...TopicNarrow(someChannel.streamId, TopicName(someTopic)).apiEncode(), | ||
{'operator': 'is', 'operand': 'unread'}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a type mismatch: apiEncode
returns a list of ApiNarrowElement, but this last item is just a Map<String, String>. It works because it's just getting passed to jsonEncode
which is pretty dynamic… but let's clean it up with uniform types. You can do that by putting an appropriate ApiNarrowElement here instead.
test/widgets/action_sheet_test.dart
Outdated
check(connection.lastRequest).isA<http.Request>() | ||
..url.path.equals('/api/v1/messages/flags/narrow') | ||
..bodyFields['narrow'].equals(jsonEncode([ | ||
...TopicNarrow(someChannel.streamId, TopicName(someTopic)).apiEncode(), | ||
{'operator': 'is', 'operand': 'unread'}, | ||
])); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This checks it's doing something to the message flags in this narrow — but not that it's marking as read. In particular this test would equally well pass if the implementation were changed to mark the messages as unread instead of read.
Let's add the checks that ensure what it's doing is marking as read, rather than marking as unread or setting or unsetting some other flag.
lib/widgets/actions.dart
Outdated
/// if the operation fails. Updates unread counts in the UI on success. | ||
static Future<void> markNarrowAsRead(BuildContext context, Narrow narrow) async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This last sentence isn't accurate — this function doesn't do anything to unread counts in the UI.
(It wouldn't, because it's the model's job to drive the data that appears in the UI. But this doesn't do anything to unread counts in the model, either. If you're thinking of the PerAccountStoreWidget.of(context).unreads.handleAllMessagesReadSuccess()
call at the end, see that method's doc.)
lib/widgets/actions.dart
Outdated
title: zulipLocalizations.errorMarkAsReadFailedTitle, | ||
message: e.toString()); // TODO(#741): extract user-facing message better | ||
return; | ||
/// High-level operations that interact with the Zulip API and handle UI feedback. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"handle feedback" sounds like something that receives feedback and does something about it. These do the opposite, showing feedback to the user.
I've just sent #1366 for this part. |
Figma doesn't specify this icon explicitly. Based on discussions in PR zulip#1274 (zulip#1274 (comment)), we chose this icon for consistency with the "Mark as read" option on web. reference: https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=3512-7&t=iwirdCVutQls9R0A-4
Figma doesn't specify this icon explicitly. Based on discussions in PR zulip#1274 (zulip#1274 (comment)), we chose this icon for consistency with the "Mark as read" option on web. reference: https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=3512-7&t=iwirdCVutQls9R0A-4
Figma doesn't specify this icon explicitly. Based on discussions in PR zulip#1274 (zulip#1274 (comment)), we chose this icon for consistency with the "Mark as read" option on web. reference: https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=3512-7&t=iwirdCVutQls9R0A-4
ee04c30
to
89b9f7c
Compare
Icon taken from the Figma design: https://www.figma.com/design/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?node-id=3512-7&t=FEydAZe5DNKVlKnV-0 Fixes: zulip#1357
89b9f7c
to
2682412
Compare
2682412
to
94e5ebe
Compare
Pushed the revision - PTAL @gnprice , Thanks! |
This PR adds a "Mark Topic as Read" button to the topic action sheet. The button appears only when there are unread messages in the topic.
Fixes #1225 and #1357
Screenshot
Screen Recording
WhatsApp.Video.2025-02-06.at.3.05.49.AM.mp4
Additional
Icons.playlist_add_check
toIcons.mark_chat_read_outlined
See CZO Discussion